
package com.rt.schedulenew.utils.coder;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;

public class PacsSecurityCoderUtil
{
    private static final Logger log;
    private static final boolean ENCRYPT = true;
    private static final boolean DECRYPT = false;
    private static byte[] defaultKey;
    private static int[] replace1C;
    private static int[] replace1D;
    private static int[] moveNum;
    private static int[] replace2;
    private static byte[] IP;
    private static byte[] E;
    private static byte[][][] S;
    private static byte[] P;
    private static byte[] rIP;
    
    private static byte[][] generateKeys(final byte[] sKey) {
        byte[] C = new byte[28];
        byte[] D = new byte[28];
        final byte[][] keys = new byte[16][48];
        for (int i = 0; i < 28; ++i) {
            C[i] = sKey[PacsSecurityCoderUtil.replace1C[i] - 1];
            D[i] = sKey[PacsSecurityCoderUtil.replace1D[i] - 1];
        }
        for (int i = 0; i < 16; ++i) {
            C = RSHR(C, PacsSecurityCoderUtil.moveNum[i]);
            D = RSHR(D, PacsSecurityCoderUtil.moveNum[i]);
            for (int j = 0; j < 48; ++j) {
                if (PacsSecurityCoderUtil.replace2[j] <= 28) {
                    keys[i][j] = C[PacsSecurityCoderUtil.replace2[j] - 1];
                }
                else {
                    keys[i][j] = D[PacsSecurityCoderUtil.replace2[j] - 29];
                }
            }
        }
        return keys;
    }
    
    private static byte[] RSHR(final byte[] b, final int n) {
        String s = new String(b);
        s = (s + s.substring(0, n)).substring(n);
        return s.getBytes();
    }
    
    private static byte[] transform(final byte[] srcBytes, final byte[] ruleBytes, final int size) {
        final byte[] desBytes = new byte[size];
        for (int i = 0; i < size; ++i) {
            desBytes[i] = srcBytes[ruleBytes[i] - 1];
        }
        return desBytes;
    }
    
    private static byte[] fFunc(final byte[] srcBytes, final byte[] key) {
        final byte[] mr = transform(srcBytes, PacsSecurityCoderUtil.E, 48);
        final byte[] xorByte = xor(mr, key);
        final byte[] sByres = sFunc(xorByte);
        return transform(sByres, PacsSecurityCoderUtil.P, PacsSecurityCoderUtil.P.length);
    }
    
    private static byte[] sFunc(final byte[] srcBytes) {
        final byte[] desBytes = new byte[32];
        for (int i = 0, a = 0, y = 0; i < 8; ++i, y += 6, a += 4) {
            final int j = (srcBytes[y] << 1) + srcBytes[y + 5];
            final int k = (srcBytes[y + 1] << 3) + (srcBytes[y + 2] << 2) + (srcBytes[y + 3] << 1) + srcBytes[y + 4];
            final byte[] temp = byte2Bit(new byte[] { PacsSecurityCoderUtil.S[i][j][k] }, 4);
            System.arraycopy(temp, 0, desBytes, a, 4);
        }
        return desBytes;
    }
    
    private static byte[] DES(final byte[] textByte, final byte[][] K, final boolean encrypt) {
        byte[] textBit = byte2Bit(textByte, 64);
        byte[] L = new byte[32];
        byte[] R = new byte[32];
        byte[] text = new byte[64];
        textBit = transform(textBit, PacsSecurityCoderUtil.IP, 64);
        System.arraycopy(textBit, 32, R, 0, 32);
        System.arraycopy(textBit, 0, L, 0, 32);
        if (encrypt) {
            for (int i = 0; i < 16; ++i) {
                final byte[] ri = fFunc(R, K[i]);
                final byte[] xorResult = xor(ri, L);
                L = R;
                R = xorResult;
            }
        }
        else {
            for (int i = 15; i >= 0; --i) {
                final byte[] li = fFunc(L, K[i]);
                final byte[] xorResult = xor(li, R);
                R = L;
                L = xorResult;
            }
        }
        System.arraycopy(L, 0, text, 0, 32);
        System.arraycopy(R, 0, text, 32, 32);
        text = transform(text, PacsSecurityCoderUtil.rIP, 64);
        return bit2Byte(text, 64);
    }
    
    private static byte[] xor(final byte[] a, final byte[] b) {
        final byte[] c = new byte[a.length];
        for (int i = 0; i < a.length; ++i) {
            c[i] = (byte)(a[i] ^ b[i]);
        }
        return c;
    }
    
    private static byte[] byte2Bit(final byte[] bytes, final int size) {
        final byte[] bits = new byte[size];
        for (int i = 0; i < size; ++i) {
            bits[i] = (byte)(bytes[i >> 3] >> (i & 0x7) & 0x1);
        }
        return bits;
    }
    
    private static byte[] bit2Byte(final byte[] bits, final int size) {
        final byte[] bytes = new byte[size >> 3];
        for (int i = 0; i < size; ++i) {
            final byte[] array = bytes;
            final int n = i >> 3;
            array[n] |= (byte)(bits[i] << (i & 0x7));
        }
        return bytes;
    }
    
    private static byte[] hexStr2CharStr(final byte[] hexBytes, final int size) {
        final byte[] chBytes = new byte[size];
        int i = 0;
        for (int j = 0; j < size; j += 2) {
            int rch = 0;
            for (int a = 0; a < 2; ++a) {
                if (hexBytes[j + a] >= 48 && hexBytes[j + a] <= 57) {
                    rch = (rch << 4) + (hexBytes[j + a] - 48);
                }
                else if (hexBytes[j + a] >= 65 && hexBytes[j + a] <= 70) {
                    rch = (rch << 4) + (hexBytes[j + a] - 65 + 10);
                }
            }
            if (rch > 128) {
                rch -= 256;
            }
            chBytes[i++] = (byte)rch;
        }
        return chBytes;
    }
    
    private static byte[] charStr2HexStr(final byte[] charBytes, final int size) {
        final byte[] hexBytes = new byte[size * 2];
        for (int i = 0, a = 0; i < size; ++i, a += 2) {
            final byte[] szHex = new byte[2];
            final byte[] temp = new byte[2];
            int charAscII = charBytes[i];
            if (charAscII < 0) {
                charAscII += 256;
            }
            temp[0] = (byte)(charAscII / 16);
            temp[1] = (byte)(charAscII % 16);
            for (int j = 0; j < 2; ++j) {
                if (temp[j] >= 0 && temp[j] <= 9) {
                    szHex[j] = (byte)(48 + temp[j]);
                }
                else {
                    szHex[j] = (byte)(65 + temp[j] - 10);
                }
            }
            System.arraycopy(szHex, 0, hexBytes, a, 2);
        }
        return hexBytes;
    }
    
    public static String decryptDES(final String src, final byte[] key) {
        final byte[] charBytes = hexStr2CharStr(src.getBytes(), src.length());
        final byte[] decryptBytes = desGo(charBytes, key, false, charBytes.length);
        for (int i = 0; i < decryptBytes.length; ++i) {
            final byte b = decryptBytes[i];
            if (b == 0) {
                return new String(Arrays.copyOf(decryptBytes, i));
            }
            if (b == -18) {
                return new String(Arrays.copyOf(decryptBytes, i - 2));
            }
        }
        return new String(decryptBytes);
    }
    
    public static String defaultDecryptDES(final String src) {
        return decryptDES(src, PacsSecurityCoderUtil.defaultKey);
    }
    
    public static String encryptDES(final String src, final byte[] key) {
        int length = src.length();
        if (length % 8 != 0) {
            length = (src.length() + 8) / 8 * 8;
        }
        final byte[] srcBytes = new byte[length];
        System.arraycopy(src.getBytes(), 0, srcBytes, 0, src.length());
        final byte[] encryptBytes = desGo(srcBytes, key, true, srcBytes.length);
        return new String(charStr2HexStr(encryptBytes, length));
    }
    
    public static String defaultEncryptDES(final String src) {
        return encryptDES(src, PacsSecurityCoderUtil.defaultKey);
    }
    
    private static byte[] desGo(final byte[] src, final byte[] key, final boolean encrypt, final int datalen) {
        final byte[] finalByte = new byte[datalen];
        if (key.length > 8) {
            final byte[] keys = new byte[16];
            System.arraycopy(key, 0, keys, 0, Math.min(key.length, 16));
            final byte[] key2 = new byte[8];
            final byte[] key3 = new byte[8];
            System.arraycopy(keys, 0, key2, 0, 8);
            System.arraycopy(keys, 8, key3, 0, 8);
            final byte[] bitKey1 = byte2Bit(key2, 64);
            final byte[] bitKey2 = byte2Bit(key3, 64);
            final byte[][] K1 = generateKeys(bitKey1);
            final byte[][] K2 = generateKeys(bitKey2);
            for (int i = 0; i < datalen; i += 8) {
                final byte[] text = new byte[8];
                System.arraycopy(src, i, text, 0, 8);
                final byte[] time1 = DES(text, K1, encrypt);
                final byte[] time2 = DES(time1, K2, !encrypt);
                final byte[] time3 = DES(time2, K1, encrypt);
                System.arraycopy(time3, 0, finalByte, i, 8);
            }
        }
        else {
            final byte[] keys = new byte[8];
            System.arraycopy(key, 0, keys, 0, key.length);
            final byte[] bitKey3 = byte2Bit(keys, 64);
            final byte[][] K3 = generateKeys(bitKey3);
            for (int j = 0; j < datalen; j += 8) {
                final byte[] text2 = new byte[8];
                System.arraycopy(src, j, text2, 0, 8);
                final byte[] time4 = DES(text2, K3, encrypt);
                System.arraycopy(time4, 0, finalByte, j, 8);
            }
        }
        return finalByte;
    }
    
    static {
        log = LoggerFactory.getLogger((Class)PacsSecurityCoderUtil.class);
        PacsSecurityCoderUtil.defaultKey = new byte[] { 0, 2, 0, 0, 9, 3, 5, 1, 9, 8, 0, 0, 9, 1, 7 };
        PacsSecurityCoderUtil.replace1C = new int[] { 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36 };
        PacsSecurityCoderUtil.replace1D = new int[] { 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4 };
        PacsSecurityCoderUtil.moveNum = new int[] { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 };
        PacsSecurityCoderUtil.replace2 = new int[] { 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32 };
        PacsSecurityCoderUtil.IP = new byte[] { 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 };
        PacsSecurityCoderUtil.E = new byte[] { 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1 };
        PacsSecurityCoderUtil.S = new byte[][][] { { { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 }, { 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 }, { 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0 }, { 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 } }, { { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 }, { 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 }, { 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15 }, { 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 } }, { { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 }, { 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 }, { 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7 }, { 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 } }, { { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 }, { 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 }, { 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4 }, { 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 } }, { { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 }, { 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 }, { 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14 }, { 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 } }, { { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 }, { 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 }, { 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6 }, { 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 } }, { { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 }, { 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 }, { 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2 }, { 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 } }, { { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 }, { 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 }, { 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8 }, { 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 } } };
        PacsSecurityCoderUtil.P = new byte[] { 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 };
        PacsSecurityCoderUtil.rIP = new byte[] { 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25 };
    }
}
